﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.ComponentModel.Design.Serialization;
using System.Drawing;

namespace InfFront.InfoSources.Base.Design
{
    public class ExpandablePolymorphTypeConvertor: TypeConverter
    {
        private TypeConverter cachedNestedConverter;
        private string cachedNestedConverterName = string.Empty;

        public ExpandablePolymorphTypeConvertor()
        {
        }

        private TypeConverter GetEffectiveTypeConverter(ITypeDescriptorContext context, object instance)
        {
            var attrs = instance.GetType().GetCustomAttributes(typeof(TypeConverterAttribute), false);
            if (attrs.Length > 0)
            {
                var tcattr = (TypeConverterAttribute) attrs[0];
                if (tcattr != null)
                {
                    if (cachedNestedConverterName != tcattr.ConverterTypeName)
                    {
                        cachedNestedConverterName = tcattr.ConverterTypeName;
                        Type converterType = Type.GetType(tcattr.ConverterTypeName);
                        cachedNestedConverter = (TypeConverter)TypeDescriptor.CreateInstance(context, converterType, null, null);
                    }
                    return cachedNestedConverter;
                }
            }
            return null;
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return ((destinationType == typeof(InstanceDescriptor)) || base.CanConvertTo(context, destinationType));
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType.Equals(typeof(string)))
                return (value != null)? value.ToString(): null;
            var effTC = GetEffectiveTypeConverter(context, value);
            if (effTC != null)
                return effTC.ConvertTo(context, culture, value, destinationType);
            return base.ConvertTo(context, culture, value, destinationType);
        }

        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            var effTC = GetEffectiveTypeConverter(context, value);
            if (effTC != null)
                return effTC.GetProperties(context, value, attributes);
            return base.GetProperties(context, value, attributes);
        }
    }

    public class BaseDataDescTypeConverter : TypeConverter
    {
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return ((destinationType == typeof(InstanceDescriptor)) || base.CanConvertTo(context, destinationType));
        }

        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            return TypeDescriptor.GetProperties(value, attributes);
        }
    }

    public class StringDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (StringDataType) value;
                var constructor = typeof(StringDataType).GetConstructor(new Type[] { typeof(string), typeof(int) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.Format, val.Length });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }

        //public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
        //{
        //    return true;
        //}

        //public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
        //{
        //    return new StringDataType((string)propertyValues["Format"], (int)propertyValues["Length"]);
        //}
    }

    public class IntDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (IntDataType)value;
                var constructor = typeof(IntDataType).GetConstructor(new Type[] { typeof(string), typeof(int), typeof(int) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.Format, val.Minimum, val.Maximum });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    public class LongDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (LongDataType)value;
                var constructor = typeof(LongDataType).GetConstructor(new Type[] { typeof(string), typeof(long), typeof(long) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.Format, val.Minimum, val.Maximum });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    public class BoolDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (BoolDataType)value;
                var constructor = typeof(BoolDataType).GetConstructor(new Type[] { typeof(string) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.Format });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    public class FloatDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (FloatDataType)value;
                var constructor = typeof(FloatDataType).GetConstructor(new Type[] { typeof(string), typeof(double), typeof(double) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.Format, val.Minimum, val.Maximum });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    public class DateTimeDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (DateTimeDataType)value;
                var constructor = typeof(DateTimeDataType).GetConstructor(new Type[] { typeof(string), typeof(DateTime), typeof(DateTime) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.Format, val.Minimum, val.Maximum });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    public class EnumDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (EnumDataType)value;
                var constructor = typeof(EnumDataType).GetConstructor(new Type[] { typeof(string), typeof(Type) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.Format, val.EnumType });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    public class ImageDataDescTypeConverter : BaseDataDescTypeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                var val = (ImageDataType)value;
                var constructor = typeof(ImageDataType).GetConstructor(new Type[] { typeof(ImageStreamFormat) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { val.StreamFormat });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

}
